/*
 *   Copyright (C) 2012  Jens Kieselbach
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You may obtain a copy of the License at http://www.gnu.org/licenses/gpl.html
 */

package de.kieselbach.javafx.builder

import de.kieselbach.javafx.builder.factory.AbstractBuilderFactory
import de.kieselbach.javafx.builder.factory.BorderPaneBuilderFactory
import de.kieselbach.javafx.builder.factory.ButtonBuilderFactory
import de.kieselbach.javafx.builder.factory.HBoxBuilderFactory
import de.kieselbach.javafx.builder.factory.SceneBuilderFactory
import javafx.stage.Modality
import javafx.stage.Stage
import de.kieselbach.javafx.builder.factory.CenterBuilderFactory
import de.kieselbach.javafx.builder.factory.TopBuilderFactory
import de.kieselbach.javafx.builder.factory.LeftBuilderFactory
import de.kieselbach.javafx.builder.factory.BottomBuilderFactory
import de.kieselbach.javafx.builder.factory.RightBuilderFactory
import de.kieselbach.javafx.builder.factory.LabelBuilderFactory
import de.kieselbach.javafx.builder.factory.TextAreaBuilderFactory
import de.kieselbach.javafx.builder.factory.TextBuilderFactory
import de.kieselbach.javafx.builder.factory.BarBuilderFactory

class UIBuilder extends BuilderSupport {

    def componentsToBePacked = [] as Set
    def dialogsToBeCentered = [] as Set

    def factoriesByName = [:]
    def factoriesByClass = [:]

    // --------------------------------------------

    UIBuilder() {

        registerFactory(new SceneBuilderFactory())
        registerFactory(new BorderPaneBuilderFactory())
        registerFactory(new HBoxBuilderFactory())
        registerFactory(new BarBuilderFactory())
        registerFactory(new ButtonBuilderFactory())
        registerFactory(new CenterBuilderFactory())
        registerFactory(new TopBuilderFactory())
        registerFactory(new LeftBuilderFactory())
        registerFactory(new BottomBuilderFactory())
        registerFactory(new RightBuilderFactory())
        registerFactory(new LabelBuilderFactory())
        registerFactory(new TextAreaBuilderFactory())
        registerFactory(new TextBuilderFactory())
    }

    void registerFactory(AbstractBuilderFactory factory) {

        factoriesByName.put(factory.name, factory)
        factoriesByClass.put(factory.nodeClass, factory)
    }

    protected void setParent(Object parent, Object child) {

        if(parent instanceof Stage) {
            parent.scene = child
        }
        else {
            def builder = factoriesByClass[parent.getClass()]
            if(builder != null) {
                builder.setParent(parent, child)
            }
            else {
                throw new IllegalArgumentException("Parent class is not registered: " + parent.getClass().name);
            }
        }
    }

    @Override
    protected void nodeCompleted(Object parent, Object node) {

        if(node instanceof Stage) {
            if(componentsToBePacked.remove(node)) {
                node.sizeToScene()
            }

            if(dialogsToBeCentered.remove(node)) {
                node.centerOnScreen()
                /*
                if(node.owner != null && node.scene != null) {

                    def owner = node.owner
                    def scene = node.scene

                    node.x = owner.x + ((owner.width - scene.width) / 2)
                    node.y = owner.y + ((owner.height - scene.height) / 2)
                }
                */
            }
        }
        else if(parent && !(parent instanceof Stage)) {
            def builder = factoriesByClass[parent.getClass()]
            if(builder != null) {
                builder.nodeCompleted(parent, node)
            }
            else {
                throw new IllegalArgumentException("Parent class is not registered: " + parent.getClass().name);
            }
        }
    }

    protected Object createNode(Object name) {

        return createNode(name, null, null)
    }

    protected Object createNode(Object name, Object value) {

        return createNode(name, null, value)
    }

    protected Object createNode(Object name, Map attributes) {

        return createNode(name, attributes, null)
    }

    protected Object createNode(Object name, Map attributes, Object value) {

        def node

        if(name == 'stage') {
            node = createStage(name, attributes, value)
        }
        else {
            def builder = factoriesByName[name]
            if(builder != null) {
                node = builder.createNode(name, attributes, value)
            }
            else {
                throw new IllegalArgumentException('Unknown node name: ' + name)
            }
        }

        node
    }

    // --------------------------------------------

    private Object createStage(Object name, Map attributes, Object value) {

        def stage = new Stage()

        if(value) {
            stage.title = value
        }

        if(attributes != null) {
            attributes.each() {key, val ->

                if(key == 'owner') {
                    if(val) {
                        stage.initOwner(val)
                    }
                }
                else if(key == 'modal') {
                    if(val) {
                        stage.initModality(Modality.WINDOW_MODAL)
                    }
                }
                else if(key == 'title') {
                    if(val) {
                        stage.title = val
                    }
                }
                else if(key == 'pack') {
                    if(val) {
                        componentsToBePacked.add(stage)
                    }
                }
                else if(key == 'center') {
                    if(val) {
                        dialogsToBeCentered.add(stage)
                    }
                }
                else {
                    stage[key] = val
                }
            }
        }

        stage
    }
}
